#pragma once
#include "DJoint.h"

namespace Skill
{
	namespace Ode
	{
		ref class DWorld;
		ref class DVector3;
		namespace Joints
		{
			ref class DJointGroup;
			public ref class DUniversal : DJoint
			{
			protected:
				virtual void CollectManagedMemory() override;
			public:
				
				///<summary>
				/// Create a new joint of the universal type.
				///</summary>
				///<param name = "world"> Wrold </param>
				///<param name = "group">
				/// set to null to allocate the joint normally.
				/// If it is valid the joint is allocated in the given joint group.
				///</param>				
				DUniversal(DWorld^ world , DJointGroup^ group);



				///<summary>
				/// Gets or set the joint anchor point, in world coordinates.
				///</summary>
				///<returns>
				/// the point on body 1. If the joint is perfectly satisfied,
				/// this will be the same as the point on body 2.
				///</returns>
				REF_PROP_DECLARATION_GETSET(DVector3,Anchor1);
				
				///<summary>
				/// Gets or set axis
				///</summary>
				REF_PROP_DECLARATION_GETSET(DVector3,Axis1);

				///<summary>
				/// Gets or set axis
				///</summary>
				REF_PROP_DECLARATION_GETSET(DVector3,Axis2);

				///<summary>
				/// set joint parameter
				///</summary>
				void SetParam(DJointParameters parameter, dReal value);	

				///<summary>
				/// Get joint parameter
				///</summary>
				dReal GetParam(DJointParameters parameter);

				///<summary>
				/// Applies torque1 about the universal's axis 1, torque2 about the
				/// universal's axis 2.
				///</summary>
				///<remarks> 
				/// This function is just a wrapper for dBodyAddTorque().
				///</remarks>
				void AddTorques(dReal torque1, dReal torque2);
				

				///<summary>
				/// Get the joint anchor point, in world coordinates.
				///</summary>
				///<returns> This returns the point on body 2. </returns>
				///<remarks>
				/// You can think of the ball and socket part of a universal joint as
				/// trying to keep the result of dJointGetBallAnchor() and
				/// dJointGetBallAnchor2() the same. If the joint is
				/// perfectly satisfied, this function will return the same value
				/// as dJointGetUniversalAnchor() to within roundoff errors.
				/// dJointGetUniversalAnchor2() can be used, along with
				/// dJointGetUniversalAnchor(), to see how far the joint has come apart.
				///</remarks>
				REF_PROP_DECLARATION_GET(DVector3,Anchor2);				

				///<summary>
				/// Get both angles at the same time.
				/// This function combine getUniversalAngle1 and getUniversalAngle2 together
				/// and try to avoid redundant calculation
				///</summary>				
				///<param name = "angle1">  The angle between the body1 and the axis 1 </param>
				///<param name = "angle2">  The angle between the body2 and the axis 2 </param>												
				void GetAngles([OutAttribute] dReal %angle1, [OutAttribute] dReal %angle2);

				///<summary>
				/// Get angle
				///</summary>				
				VALUE_PROP_DECLARATION_GET(dReal,Angle1);

				///<summary>
				/// Get angle
				///</summary>				
				VALUE_PROP_DECLARATION_GET(dReal,Angle2);
				
				///<summary>
				/// Get time derivative of angle
				///</summary>				
				VALUE_PROP_DECLARATION_GET(dReal,Angle1Rate);
				
				///<summary>
				/// Get time derivative of angle
				///</summary>				
				VALUE_PROP_DECLARATION_GET(dReal,Angle2Rate);
			};
		}
	}
}